package com.nf.practice.controller;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.nf.practice.common.util.CompressDownloadUtil;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.DateUtils;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.text.SimpleDateFormat;
import java.time.format.DateTimeParseException;
import java.util.*;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;


@RestController
@RequestMapping("/practice/user")
public class FileController {

    @GetMapping("/downLoadAllFile")
    public void downLoadAllFile(HttpServletResponse response, @RequestParam("appNo")String appNo) throws IOException {
        // 自测：http://127.0.0.1:8081/practice/user/downLoadAllFile?appNo=01202303271428101354
        // 3、通过单号查询该单号下的所有影像件
        // 影像件测试地址
        String picUrl = "http://172.16.10.5:31312";

        Map<String,Object> reqMap = new HashMap<>();
        reqMap.put("appNo", appNo);

        String json = JSON.toJSONString(reqMap);
        CloseableHttpClient client = HttpClients.createDefault();
        HttpPost post = new HttpPost(picUrl + "/file-system/picture/queryImgListAll");
        String resStr = null;
        try {
            StringEntity s = new StringEntity(json);
            s.setContentEncoding("UTF-8");
            s.setContentType("application/json");//发送json数据需要设置contentType
            post.setEntity(s);
            HttpResponse res = client.execute(post);
            if(res.getStatusLine().getStatusCode() == HttpStatus.SC_OK){
                resStr = EntityUtils.toString(res.getEntity());
            }
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }

        JSONObject jsonData = JSONObject.parseObject(resStr);
        List<JSONObject> list = JSONObject.parseArray(jsonData.getJSONArray("data").toJSONString(), JSONObject.class);

        List<String> fileKeys = new ArrayList<>();
        for (JSONObject jsonObject : list) {
            if (StringUtils.isNotBlank(jsonObject.getString("filePath"))) {
                fileKeys.add(jsonObject.getString("filePath"));
            }
        }

        //-- 2、转换成文件列表
//        List<File> files = new ArrayList<>();
//        for (JSONObject jsonObject : list) {
//            if (StringUtils.isNotBlank(jsonObject.getString("filePath"))) {
//                files.add(new File(jsonObject.getString("filePath")));
//            }
//        }

        List<String> files = new ArrayList<>();
        for (JSONObject jsonObject : list) {
            if (StringUtils.isNotBlank(jsonObject.getString("filePath"))) {
                files.add(jsonObject.getString("filePath"));
            }
        }

        //-- 检查需要下载多文件列表中文件路径是否都存在
//        for (File file : files) {
//            if (!file.exists()) {
//                //-- 需要下载的文件中存在不存在地址
//                return ;
//            }
//        }

        //-- 3、响应头的设置
        Date date = new Date();
        String downloadName = dateToString(date, "yyyyMMdd") + dateToString(date,"HHmmss") + ".zip";
        response = CompressDownloadUtil.setDownloadResponse(response, downloadName);

        //-- 4、第一种方案：
        //-- 指定ZIP压缩包路径
//		String zipFilePath = this.setZipFilePath(downloadName);
//		try {
//			//-- 将多个文件压缩到指定路径下
//			CompressDownloadUtil.compressZip(files, new FileOutputStream(zipFilePath));
//			//-- 下载压缩包
//			CompressDownloadUtil.downloadFile(response.getOutputStream(), zipFilePath);
//			//-- 删除临时生成的ZIP文件
//			CompressDownloadUtil.deleteFile(zipFilePath);
//		} catch (IOException e) {
//			Xlogger.error(XMsgError.buildSimple(CompressDownloadUtil.class.getName(), "downloadallfiles", e));
//		}

        //-- 5、第二种方案：
        try {
            //-- 将多个文件压缩写进响应的输出流
            CompressDownloadUtil.compressZip(list, response.getOutputStream());
        } catch (IOException e) {
//            Xlogger.error(XMsgError.buildSimple(CompressDownloadUtil.class.getName(), "downloadallfiles", e));
            System.out.println(e.getMessage());
        }

        System.out.println("下载结束====================");

    }

    public String dateToString(Date date, String format) {
        try {
            SimpleDateFormat formatter = new SimpleDateFormat(format);
            return formatter.format(date);

        } catch (DateTimeParseException e) {
            e.printStackTrace();
        }
        return null;
    }

    @GetMapping("/download")
    public void downLoadFile(HttpServletResponse response, @RequestParam("appNo")String appNo) throws IOException {
        // 自测：http://127.0.0.1:8081/practice/user/download?appNo=01202303271428101354
        // 3、通过单号查询该单号下的所有影像件
        // 影像件测试地址
        String picUrl = "http://172.16.10.5:31312";

        Map<String,Object> reqMap = new HashMap<>();
        reqMap.put("appNo", appNo);

        String json = JSON.toJSONString(reqMap);
        CloseableHttpClient client = HttpClients.createDefault();
        HttpPost post = new HttpPost(picUrl + "/file-system/picture/queryImgListAll");
        String resStr = null;
        try {
            StringEntity s = new StringEntity(json);
            s.setContentEncoding("UTF-8");
            s.setContentType("application/json");//发送json数据需要设置contentType
            post.setEntity(s);
            HttpResponse res = client.execute(post);
            if(res.getStatusLine().getStatusCode() == HttpStatus.SC_OK){
                resStr = EntityUtils.toString(res.getEntity());
            }
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }

        JSONObject jsonData = JSONObject.parseObject(resStr);
        List<JSONObject> list = JSONObject.parseArray(jsonData.getJSONArray("data").toJSONString(), JSONObject.class);

//        List<String> fileKeys = list.stream().map(x -> x.getJSONObject("filePath").toString()).collect(Collectors.toList());
        List<String> fileKeys = new ArrayList<>();
        for (JSONObject jsonObject : list) {
            if (StringUtils.isNotBlank(jsonObject.getString("filePath"))) {
                fileKeys.add(jsonObject.getString("filePath"));
            }
        }

        //判断是否为空
        if (!CollectionUtils.isEmpty(fileKeys)){
            response.setContentType("application/octet-stream;charset=utf-8");
            if (fileKeys.size() == 1) {
                String fileUrl = fileKeys.get(0);
                String[] arr = fileUrl.split("/");
                String fileName = arr[arr.length - 1].split("\\?")[0];
                response.reset();
                response.setHeader("Content-Disposition", "attachment;filename=" + fileName);
                try {
                    downloadFile(fileUrl, response.getOutputStream());
                } catch (IOException e) {
//                    log.error("下载文件失败", e);
                    System.out.println("下载文件失败");
                }
            } else {
                //多文档下载，以zip包形式下载
                String zipFileName = System.currentTimeMillis()+"zonglv.zip";
                response.reset();
                response.setHeader("Content-Disposition", "attachment;filename=" + zipFileName);
                try {
                    downloadZipPackage(fileKeys, response.getOutputStream());
                } catch (IOException e) {
//                    log.error("下载文件失败", e);
                    System.out.println("下载文件失败");
                }
            }
        } else {
//            log.error("未选择任何待下载文件，请先勾选待下载文件！", "", "error");
            System.out.println("未选择任何待下载文件，请先勾选待下载文件！");
        }
    }

    /**
     * 单文件下载
     * @param filePath
     * @param os
     * @throws IOException
     */
    public void downloadFile(String filePath, OutputStream os) throws IOException{
        FileInputStream fis = null;
        try
        {
            File file = new File(filePath);
            if (!file.exists())
            {
                throw new FileNotFoundException(filePath);
            }
            fis = new FileInputStream(file);
            byte[] b = new byte[1024];
            int length;
            while ((length = fis.read(b)) > 0)
            {
                os.write(b, 0, length);
            }
        }
        catch (IOException e)
        {
            throw e;
        }
        finally
        {
            if (os != null)
            {
                try
                {
                    os.close();
                }
                catch (IOException e1)
                {
                    e1.printStackTrace();
                }
            }
            if (fis != null)
            {
                try
                {
                    fis.close();
                }
                catch (IOException e1)
                {
                    e1.printStackTrace();
                }
            }
        }
    }

    /**
     * 多文件下载
     * @param fileUrls
     * @param out
     * @throws IOException
     */
    public void downloadZipPackage(List<String> fileUrls, OutputStream out) throws IOException {
        //将输出流转换成Zip输出流
        ZipOutputStream zos = new ZipOutputStream(out);
        List<String> fileNames = new ArrayList<>();
        for (String filePath : fileUrls) {
            //判断文件是否为空
            if(filePath.isEmpty()){
                continue;
            }

            //根据Url获取文件名
            String[] arr = filePath.split("/");
            String fileName = arr[arr.length - 1].split("\\?")[0];
            if (fileNames.contains(fileName)) {
                //如果文件有重名，会自动修改文件名，防止打包出错
                fileName = System.currentTimeMillis() + fileName;
            }
            fileNames.add(fileName);
            //这里的目录结构只是举例，可以是任何目录，相同目录前缀的文件将会被放在一起，不同的就会分开存放
//            StringBuilder dirName = new StringBuilder();
//            int len = arr.length;
//            for(int i=0;i<len-1;i++){
//                if(arr[i] !=""){
//                    dirName.append(arr[i]+"/");
//                }
//            }
//            //文件结构
//            fileName = dirName.toString() + File.separator + fileName;
            zos.putNextEntry(new ZipEntry(fileName));
            //获取文件的输入流
            InputStream fis = null;
            try {
                File file = new File(filePath);
                if (!file.exists()) {
                    continue;
                }
//                fis = new FileInputStream(file);
//                byte[] buffer = new byte[2048];
//                int r;
//                while ((r = fis.read(buffer)) != -1) {
//                    zos.write(buffer, 0, r);
//                }

                URL url = new URL(filePath);
                HttpURLConnection conn = (HttpURLConnection)url.openConnection();
                //设置超时间为3秒
                conn.setConnectTimeout(5*1000);
                //防止屏蔽程序抓取而返回403错误
                conn.setRequestProperty("User-Agent", "Mozilla/4.0 (compatible; MSIE 5.0; Windows NT; DigExt)");
                //得到输入流
                fis = conn.getInputStream();
                //获取自己数组
                byte[] getData = readInputStream(fis);
                zos.write(getData);

            }catch (IOException e) {
                if(fis !=null){
                    fis.close();
                }
                continue;
            } finally {
                if (fis != null)
                    fis.close();
            }
        }
        zos.flush();
        zos.close();
    }


    /**
     * 从输入流中获取字节数组
     * @param inputStream
     * @return
     * @throws IOException
     */
    public static  byte[] readInputStream(InputStream inputStream) throws IOException {
        byte[] buffer = new byte[1024];
        int len = 0;
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        while((len = inputStream.read(buffer)) != -1) {
            bos.write(buffer, 0, len);
        }
        bos.close();
        return bos.toByteArray();
    }


}
